#include "../include/debugger.h"

std::vector<word> breakpoints;

extern byte codes[0x10000];
extern byte data[0x10000];
extern byte stack[0x10000];
extern byte buffer[0x10000];

extern qword iregs[128];
extern real4 fregs[64];
extern real8 dregs[64];

void viewer(const char *type, const char *value)
{
	word target = 0;
	if (value != nullptr)
		target = std::stoi(value, nullptr, 16);
	if (strcmp(type, "help") == 0)
		std::cout
			<< "Type \'help\' to show tihs help message.\n"
			<< "codes: receive a 16bit address,check the target block code memory values.\n"
			<< "datas:receive a 16bit address,check the target block data memory values.\n"
			<< "stack:receive a 16bit address,check the target block stack memory values.\n"
			<< "buffer:receive a 16bit address,check the target block buffer memory values.\n"
			<< "int_regs:receive a 8bit address,check the target block int_regs register values.\n"
			<< "float_regs:receive a 8bit address,check the target block float_regs register values.\n"
			<< "double_regs:receive a 8bit address,check the target block double_regs register values.\n"
			<< std::endl;
	else if (strcmp(type, "codes") == 0)
		for (int i = 0; i < 128; i++)
		{
			printf("0x%02x ", (unsigned char)codes[target + i]);
			if (i % 16 == 15)
				printf("\n");
			if (i % 16 == 7)
				printf(" ");
		}
	else if (strcmp(type, "datas") == 0)
		for (int i = 0; i < 128; i++)
		{
			printf("0x%02x ", (unsigned char)data[target + i]);
			if (i % 16 == 15)
				printf("\n");
			if (i % 16 == 7)
				printf(" ");
		}
	else if (strcmp(type, "stack") == 0)
		for (int i = 0; i < 128; i++)
		{
			printf("0x%02x ", (unsigned char)stack[target + i]);
			if (i % 16 == 15)
				printf("\n");
			if (i % 16 == 7)
				printf(" ");
		}
	else if (strcmp(type, "buffer") == 0)
		for (int i = 0; i < 128; i++)
		{
			printf("0x%02x ", (unsigned char)buffer[target + i]);
			if (i % 16 == 15)
				printf("\n");
			if (i % 16 == 7)
				printf(" ");
		}
	else if (strcmp(type, "int_regs") == 0)
		printf("Int Register 0x%02x : 0x%016llx\n", target & 0x7f, iregs[target & 0x7f]);
	else if (strcmp(type, "float_regs") == 0)
		printf("Float Register 0x%02x : %f\n", target & 0x3f, fregs[target & 0x3f]);
	else if (strcmp(type, "double_regs") == 0)
		printf("Double Register 0x%02x : %f\n", target & 0x3f, dregs[target & 0x3f]);
}
#ifdef __debug__
void debug()
{
	std::string operation, value, value2;
	std::cin >> operation;
	if (operation == "help")
		std::cout << "Type \'help\' to show this help message.\n"
				  << "print:check the machine value.\n"
				  << "add_break:add a breakpoint.\n"
				  << "remove_break:remove a breakpoint.\n"
				  << "print_break:print all breakpoints.\n"
				  << "step:debug system step by step.\n"
				  << "break:run to the breakpoint.\n"
				  << "execute:run through the program.\n"
				  << std::endl;
	else if (operation == "print")
	{
		std::cin >> value >> value2;
		viewer(value.c_str(), value2.c_str());
	}
	else if (operation == "add_break")
	{
		std::cin >> value;
		if (std::find(breakpoints.begin(), breakpoints.end(), std::stoi(value, nullptr, 16)) == breakpoints.end())
			breakpoints.push_back(std::stoi(value, nullptr, 16));
	}
	else if (operation == "remove_break")
	{
		std::cin >> value;
		if (std::find(breakpoints.begin(), breakpoints.end(), std::stoi(value, nullptr, 16)) != breakpoints.end())
			breakpoints.erase(std::remove(breakpoints.begin(), breakpoints.end(), std::stoi(value, nullptr, 16)), breakpoints.end());
	}
	else if (operation == "print_breaks")
		for (int i = 0; i < breakpoints.size(); i++)
			std::cout << "Breakpoint " << i << ": " << breakpoints[i] << std::endl;
	else if (operation == "execute")
		while ((iregs[Flag] & RUNNING) && !(iregs[Flag] & (ERROR + DEBUG)))
			selector(loader());
	else if (operation == "step")
		selector(loader());
	else if (operation == "bdebug")
		while ((iregs[Flag] & RUNNING) && !(iregs[Flag] & (ERROR + DEBUG)))
		{
			selector(loader());
			if (std::find(breakpoints.begin(), breakpoints.end(), iregs[Code]) != breakpoints.end())
				return;
		}
	else if (operation == "quit")
		exit(0);
	else
		std::cout << "Invalid Command!" << std::endl;
}
#else
void debug(int argc, char **argv)
{
	char operation = 0;
	std::string type, value;
	if (strcmp(argv[0], "execute") == 0)
	{
		std::cout << "Mode:execute.\n";
		while ((iregs[Flag] & RUNNING) && !(iregs[Flag] & (ERROR + DEBUG)))
			selector(loader());
	}
	else if (strcmp(argv[0], "debug") == 0)
	{
		std::cout << "Mode:debug.\n";
		while (operation != 'q')
		{
			std::cout << "press \'n\' to next command, \'q\' to quit, \'r\' to execute,or input\'p\' to check the values.\n";
			std::cin >> operation;
			switch (operation)
			{
			case 'n':
				if ((iregs[Flag] & RUNNING) && !(iregs[Flag] & (ERROR + DEBUG)))
					selector(loader());
				else
					std::cout << "The program has run over.\n";
				break;
			case 'r':
				while ((iregs[Flag] & RUNNING) && !(iregs[Flag] & (ERROR + DEBUG)))
					selector(loader());
				break;
			case 'p':
				std::cin >> type >> value;
				viewer(type.c_str(), value.c_str());
				break;
			case 'q':
				exit(0);
				break;
			default:
				std::cout << "Invalid Command,run next command." << std::endl;
			}
		}
	}
}
#endif